﻿using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Deployment.Application;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Shell;
using System.Threading.Tasks;

using System.IO;

using ScarecrowLibrary;
using ScarecrowLibrary.Network;
using ScarecrowLibrary.IO;

namespace Scarecrow_Network_Manager
{
    // TODO : Controllare la connessione di rete e attivare i profili in automatico
    /// <summary>
    /// Logica di interazione per MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        enum WorkerTasks
        {
            LoadingProfiles, ActivatingProfile, RepairingNetwork, Exception
        }

        #region Fields
        BackgroundWorker worker;
        static ProfileControl selected, active, lastActivated;
        #endregion

        #region Methods

        void LoadTaskbarItemInfo()
        {
            try
            {
                //Aggiungo i tasti speciali
                ThumbButtonInfo repair = new ThumbButtonInfo();
                repair.Description = Properties.Resources.Repair;
                repair.ImageSource = Global.LoadImageFromResource("Images\\System\\tools.png").Source;
                repair.Click += new EventHandler(repair_Click);
                this.TaskbarItemInfo.ThumbButtonInfos.Add(repair);

                ThumbButtonInfo close = new ThumbButtonInfo();
                close.Description = Properties.Resources.Close;
                close.ImageSource = Global.LoadImageFromResource("Images\\System\\delete2.png").Source;
                close.Click += new EventHandler(close_Click);
                this.TaskbarItemInfo.ThumbButtonInfos.Add(close);
            }
            catch (Exception exc)
            {
                Global.NotifyCrash(exc);
            }
        }


        #region Worker Methods
        bool StartWorker(object argument)
        {
            try
            {
                if (!this.worker.IsBusy)
                {
                    this.IsEnabled = false;
                    this.spInfo.Visibility = System.Windows.Visibility.Visible;
                    TaskbarItemInfo.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Normal;
                    this.worker.RunWorkerAsync(argument);
                    return true;
                }
            }
            catch (Exception exc)
            {
                Global.NotifyCrash(exc);
            }
            return false;
        }

        void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            try
            {
                this.prgBar.Value = 0;
                this.prgBar.IsIndeterminate = false;
                lblInfo.Content = null;
                this.spInfo.Visibility = System.Windows.Visibility.Collapsed;
                TaskbarItemInfo.ProgressState = System.Windows.Shell.TaskbarItemProgressState.None;
                this.IsEnabled = true;
                this.txtFilter.Focus();
                //se il profilo non è stato attivato correttamente
                if (e.Result != null && !((bool)e.Result))
                {
                    //segnalo l'errore e riprovo
                    if (MessageBox.Show(Properties.Resources.ActivatingFailed, Properties.Resources.Warning, MessageBoxButton.YesNo) == MessageBoxResult.Yes)
                    {
                        StartWorker(WorkerTasks.ActivatingProfile);
                    }
                }
                else if (e.Result != null && ((bool)e.Result))
                {
                    lastActivated = active;
                    active = selected;

                    lastActivated.IsActive = false;
                    active.IsActive = true;
                }
            }
            catch (Exception exc)
            {
                Global.NotifyCrash(exc);
            }
        }

        // Args : [ TASK , Description, arg1, arg2, ... argN ]
        void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            try
            {
                this.prgBar.Value = e.ProgressPercentage;
                TaskbarItemInfo.ProgressValue = (double)e.ProgressPercentage / 100.0;

                object[] args = (object[])e.UserState;

                WorkerTasks task = (WorkerTasks)args[0];
                this.lblInfo.Content = (string)args[1];

                switch (task)
                {
                    case WorkerTasks.LoadingProfiles:
                        if (args[2] != null && args[3] != null)
                        {
                            bool match = (bool)args[2];
                            scNetworkProfile np = args[3] as scNetworkProfile;
                            ProfileControl pc = new ProfileControl(np);
                            if (Properties.Settings.Default.Bookmarks.Contains(np.Name))
                            {
                                pc.imgBookmark.Opacity = 1.0;
                                pc.imgBookmark.Tag = "active";
                                ThumbButtonInfo tbi = new ThumbButtonInfo();
                                tbi.Description = pc.Profile.Name;
                                tbi.ImageSource = Global.LoadImageFromPath(pc.Profile.ImagePath).Source;
                                tbi.Click += new EventHandler(tbi_Click);
                                TaskbarItemInfo.ThumbButtonInfos.Insert(0, tbi);
                            }
                            else
                            {
                                pc.imgBookmark.Tag = "!active";
                            }

                            if (match)
                            {
                                pc.txtTitle.Background = Brushes.Green;
                                pc.IsActive = true;
                                this.lstProfiles.Items.Insert(0, pc);
                                active = pc;
                            }
                            else
                            {
                                this.lstProfiles.Items.Add(pc);
                            }
                        }
                        break;
                    case WorkerTasks.ActivatingProfile:
                        break;
                    case WorkerTasks.RepairingNetwork:
                        this.TaskbarItemInfo.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Indeterminate;
                        this.prgBar.IsIndeterminate = true;
                        break;
                    case WorkerTasks.Exception:
                        Global.NotifyCrash(args[2] as Exception);
                        break;
                    default:
                        break;
                }
            }
            catch (Exception exc)
            {
                Global.NotifyCrash(exc);
            }
        }

        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            // Do Work
            // Args = [task, var, var]
            try
            {
                WorkerTasks task = (WorkerTasks)e.Argument;
                switch (task)
                {
                    case WorkerTasks.LoadingProfiles:
                        this.worker.ReportProgress(0, new object[] { task, Properties.Resources.LoadingProfile, null, null });

                        //al primo avvio aggiorno la lista delle interfacce
                        Global.Nics = scNetworkAdapter.GetAllInterfaces();


                        bool match = false, matchFlag = false;

                        //Carico i profili salvati
                        string[] files = System.IO.Directory.GetFiles(Global.ProfilesPath);

                        for (int i = 0; i < files.Length; i++)
                        {
                            string file = files[i];
                            if (System.IO.Path.GetFileNameWithoutExtension(file) == Properties.Resources.UnknowProfile)
                            {
                                System.IO.File.Delete(file);
                            }
                            else
                            {
                                scNetworkProfile np = scSerializer.Deserialize(File.ReadAllBytes(file)) as scNetworkProfile;

                                //Genero il profilo corrente
                                scNetworkProfile current = Global.GetCheckProfile(np);
                                matchFlag |= match = np == current;
                                this.worker.ReportProgress(i * 100 / files.Length, new object[] { task, np.Name, match, np });
                            }
                        }
                        // non è attivo nessun profilo conosciuto
                        if (!matchFlag)
                        {
                            scNetworkProfile current = scNetworkProfile.GetCurrentProfile();
                            current.Name = Properties.Resources.UnknowProfile;
                            current.ImagePath = System.IO.Path.Combine("Images\\Profiles", "dhcp.png");
                            File.WriteAllBytes(System.IO.Path.Combine(Global.ProfilesPath, Properties.Resources.UnknowProfile), scSerializer.Serialize(current));
                            this.worker.ReportProgress(100, new object[] { task, current.Name, true, current });
                        }
                        break;
                    case WorkerTasks.ActivatingProfile:
                        if (selected != null)
                        {
                            scNetworkProfile np = selected.Profile;
                            scAdapterProfile[] profiles = np.GetProfiles();

                            //Determino quale scheda devo attivare
                            profiles = profiles.Where((p) => p.Enabled).ToArray();
                            scAdapterProfile profile = profiles[0];

                            int percent = 0;
                            //Determino tutte le altre schede
                            //Notifico l'analisi del sistema.
                            this.worker.ReportProgress(percent, new object[] { task, Properties.Resources.GatheringInformation });

                            int step = 25 / Global.Nics.Length;

                            //scorro tutte le schede
                            for (int i = 0; i < Global.Nics.Length; i++)
                            {
                                if (this.worker.CancellationPending)
                                {
                                    e.Result = true;
                                    return;
                                }
                                try
                                {
                                    // Notifico che inizio ad elaborare la scheda
                                    scNetworkAdapter adapter = Global.Nics[i];

                                    //se devo attivare la scheda corrente
                                    if (adapter.ConnectionName == profile.NetworkAdapter)
                                    {
                                        //Notifico l'attivazione della scheda
                                        percent += step;
                                        this.worker.ReportProgress(percent, new object[] { task, string.Format("{0} {1}", Properties.Resources.EnablingAdapter, adapter.ConnectionName) });
                                        adapter.Enable();

                                        if (this.worker.CancellationPending)
                                        {
                                            e.Result = true;
                                            return;
                                        }

                                        if (profile.IsIPDhcp)
                                        {
                                            // Notifico l'impostazione della configurazione DHCP
                                            percent += step;
                                            this.worker.ReportProgress(percent, new object[] { task, Properties.Resources.ConfiguringDHCPIP });
                                            adapter.SetIPDHCP();
                                        }
                                        else
                                        {
                                            // Notifico l'impostazione della configurazione Manuale
                                            percent += step;
                                            this.worker.ReportProgress(percent, new object[] { task, Properties.Resources.ConfiguringStaticIP });
                                            adapter.SetIPAddress(profile.IPAddress, profile.SubnetMask, profile.Gateway);
                                        }

                                        if (this.worker.CancellationPending)
                                        {
                                            e.Result = true;
                                            return;
                                        }

                                        if (profile.IsDNSDhcp)
                                        {
                                            // Notifica
                                            percent += step;
                                            this.worker.ReportProgress(percent, new object[] { task, Properties.Resources.ConfiguringDHCPDNS });
                                            adapter.SetDNSDHCP();
                                        }
                                        else
                                        {
                                            // Notifica
                                            percent += step;
                                            this.worker.ReportProgress(percent, new object[] { task, Properties.Resources.ConfiguringStaticDNS });
                                            adapter.SetDNS(profile.DNS1, profile.DNS2);
                                        }
                                    }
                                    else
                                    {
                                        // Notifica
                                        percent += step;
                                        this.worker.ReportProgress(percent, new object[] { task, string.Format("{0} {1}", Properties.Resources.DisablingAdapter, adapter.ConnectionName) });
                                        adapter.Disable();

                                        if (this.worker.CancellationPending)
                                        {
                                            e.Result = true;
                                            return;
                                        }

                                        percent += 2 * step;
                                    }
                                }
                                catch
                                {
                                }
                            }

                            // restituisco true o false a seconda che l'operazione sia andata bene o male

                            percent = 100;
                            this.worker.ReportProgress(percent, new object[] { task, Properties.Resources.CheckActiveProfile });

                            //Ogni volta che attivo un profilo aggiorno la lista delle interfacce
                            Global.Nics = scNetworkAdapter.GetAllInterfaces();

                            scNetworkProfile check = Global.GetCheckProfile(np);

                            e.Result = np == check;
                        }
                        break;
                    case WorkerTasks.RepairingNetwork:
                        try
                        {
                            if (selected != null)
                            {
                                scAdapterProfile[] profiles = selected.Profile.GetProfiles();
                                profiles = profiles.Where((p) => p.Enabled).ToArray();
                                scNetworkAdapter adapter = new scNetworkAdapter(profiles[0].NetworkAdapter);
                                this.worker.ReportProgress(0, new object[] { task, Properties.Resources.Repairing + adapter.ConnectionName });
                                adapter.Repair();
                            }
                        }
                        catch (Exception exc)
                        {
                            this.worker.ReportProgress(0, new object[] { WorkerTasks.Exception, "Eccezione", exc });
                        }
                        break;
                    default:
                        break;
                }
            }
            catch (Exception exc)
            {
                this.worker.ReportProgress(0, new object[] { WorkerTasks.Exception, "Eccezione", exc });
            }
        }
        #endregion

        #region Forms Methods

        public void close_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.GetCurrentProcess().Kill();
        }

        public void repair_Click(object sender, EventArgs e)
        {
            StartWorker(WorkerTasks.RepairingNetwork);
        }

        public void tbi_Click(object sender, EventArgs e)
        {
            try
            {
                //Abilita profilo
                ThumbButtonInfo tbi = (sender as ThumbButtonInfo);
                for (int i = 0; i < lstProfiles.Items.Count; i++)
                {
                    if ((lstProfiles.Items[i] as ProfileControl).Profile.Name == tbi.Description)
                    {
                        lstProfiles.SelectedIndex = i;
                        break;
                    }
                }
                //Seleziono il profilo
            }
            catch (Exception exc)
            {
                Global.NotifyCrash(exc);
            }
            StartWorker(WorkerTasks.ActivatingProfile);
        }
        public MainWindow()
        {
            try
            {
                //Inizializzo le impostazioni
                if (Properties.Settings.Default.Bookmarks == null)
                    Properties.Settings.Default.Bookmarks = new System.Collections.Specialized.StringCollection();

                // set language
                System.Threading.Thread.CurrentThread.CurrentCulture = System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(Properties.Settings.Default.Language);

                InitializeComponent();

                #region First Run
                //Controllo se questo è il primo avvio
                if (System.IO.File.Exists(@"\firstrun.txt"))
                {
                    //Cancello il file di flag
                    System.IO.File.Delete(@"\firstrun.txt");

                }

                //Creo le directory di sistema
                //Se le directory non esistono
                if (!System.IO.Directory.Exists(Global.ProfilesPath))
                    System.IO.Directory.CreateDirectory(Global.ProfilesPath);

                if (!System.IO.Directory.Exists(Global.ImagesPath))
                    System.IO.Directory.CreateDirectory(Global.ImagesPath);

                #endregion

                LoadTaskbarItemInfo();

                #region Updater

                if (ApplicationDeployment.IsNetworkDeployed)
                {
                    ApplicationDeployment.CurrentDeployment.CheckForUpdateProgressChanged += new DeploymentProgressChangedEventHandler(CurrentDeployment_CheckForUpdateProgressChanged);
                    ApplicationDeployment.CurrentDeployment.CheckForUpdateCompleted += new CheckForUpdateCompletedEventHandler(CurrentDeployment_CheckForUpdateCompleted);
                    ApplicationDeployment.CurrentDeployment.UpdateProgressChanged += new DeploymentProgressChangedEventHandler(CurrentDeployment_UpdateProgressChanged);
                    ApplicationDeployment.CurrentDeployment.UpdateCompleted += new AsyncCompletedEventHandler(CurrentDeployment_UpdateCompleted);

                    ApplicationDeployment.CurrentDeployment.CheckForUpdateAsync();
                }
                else
                {
                    this.lblVersion.Content = string.Format("{0}: {1}", Properties.Resources.DebugVersion, scEnvironment.ApplicationVersion);
                }

                #endregion

                #region Worker
                this.worker = new BackgroundWorker();
                this.worker.WorkerReportsProgress = true;
                this.worker.WorkerSupportsCancellation = true;
                this.worker.DoWork += new DoWorkEventHandler(worker_DoWork);
                this.worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
                this.worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
                #endregion
            }
            catch (Exception exc)
            {
                Global.NotifyCrash(exc);
            }
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            StartWorker(WorkerTasks.LoadingProfiles);
        }

        private void cmdAddProfile_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                //Visualizzo la finestra per creare il profilo
                //Attendo il risultato
                //Se il risultato è un profilo valido, lo aggiungo alla lista
                ProfileWindow window = new ProfileWindow(null);
                window.ShowDialog();
                //aggiungo il nuovo profilo
                if (!string.IsNullOrWhiteSpace(window.ProfilePath))
                {
                    scNetworkProfile np = scSerializer.Deserialize(File.ReadAllBytes(window.ProfilePath)) as scNetworkProfile;
                    ProfileControl pc = new ProfileControl(np);
                    this.lstProfiles.Items.Add(pc);
                }
            }
            catch (Exception exc)
            {
                Global.NotifyCrash(exc);
            }
        }

        private void cmdEditProfile_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                string profileName = selected.txtTitle.Text;
                if (profileName.Contains(Environment.NewLine))
                    profileName = profileName.Remove(profileName.LastIndexOf(Environment.NewLine));
                ProfileWindow window = new ProfileWindow(System.IO.Path.Combine(Global.ProfilesPath, profileName));
                window.ShowDialog();
                if (!string.IsNullOrWhiteSpace(window.ProfilePath))
                {
                    //Carico il nuovo profilo
                    scNetworkProfile np = scSerializer.Deserialize(File.ReadAllBytes(window.ProfilePath)) as scNetworkProfile;

                    //Se ho cambiato il nome, devo rimuoverlo dai preferiti
                    if (selected.Profile.Name != np.Name)
                        Properties.Settings.Default.Bookmarks.Remove(selected.Profile.Name);

                    //se ho effettuato delle modifiche
                    //tolgo il vecchio oggetto
                    this.lstProfiles.Items.Remove(selected);

                    //e inserisco quello nuovo
                    ProfileControl pc = new ProfileControl(np);
                    if (Properties.Settings.Default.Bookmarks.Contains(np.Name))
                    {
                        pc.imgBookmark.Opacity = 1.0;
                        pc.imgBookmark.Tag = "active";
                    }
                    else
                    {
                        pc.imgBookmark.Tag = "!active";
                    }

                    this.lstProfiles.Items.Add(pc);
                    if (Global.GetCheckProfile(np) == np)
                    {
                        pc.txtTitle.Background = Brushes.Green;
                        pc.IsActive = true;
                    }
                    this.lstProfiles.Items.Refresh();
                }
            }
            catch (Exception exc)
            {
                Global.NotifyCrash(exc);
            }
        }

        private void cmdRepair_Click(object sender, RoutedEventArgs e)
        {
            StartWorker(WorkerTasks.RepairingNetwork);
        }
        private void lstProfiles_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            cmdEditProfile.IsEnabled = cmdRemoveProfile.IsEnabled = (lstProfiles.SelectedItem != null);
            try
            {
                this.cmdActivateProfile.Visibility = (this.lstProfiles.SelectedItem == null) ? Visibility.Collapsed : Visibility.Visible;
                selected = (this.lstProfiles.SelectedItem as ProfileControl);
                this.txtFilter.Focus();
            }
            catch (Exception exc)
            {
                Global.NotifyCrash(exc);
            }
        }

        private void cmdActivateProfile_Click(object sender, RoutedEventArgs e)
        {
            StartWorker(WorkerTasks.ActivatingProfile);
        }

        private void cmdRemoveProfile_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (selected != null && selected.Name != Properties.Resources.UnknowProfile && selected.Name != Properties.Resources.UnknowProfile)
                {
                    if (MessageBox.Show(Properties.Resources.DeletingProfile, Properties.Resources.Warning, MessageBoxButton.YesNo) == MessageBoxResult.Yes)
                    {
                        System.IO.File.Delete(System.IO.Path.Combine(Global.ProfilesPath, selected.Profile.Name));
                        // TODO : Animazione profilo eliminato
                        lstProfiles.Items.Remove(selected);
                    }
                }
            }
            catch (Exception exc)
            {
                Global.NotifyCrash(exc);
            }
        }
        private void cmdOptions_Click(object sender, RoutedEventArgs e)
        {
            SettingsWindow window = new SettingsWindow();
            window.ShowDialog();
        }

        private void Window_Closing(object sender, CancelEventArgs e)
        {
            if (e.Cancel = Properties.Settings.Default.NotifyHide)
                this.WindowState = System.Windows.WindowState.Minimized;
        }
        #endregion

        #region Updater
        private void cmdUpdate_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                ApplicationDeployment.CurrentDeployment.UpdateAsync();
                this.cmdUpdate.IsEnabled = false;
            }
            catch (Exception exc)
            {
                Global.NotifyCrash(exc);
            }
        }
        void CurrentDeployment_UpdateProgressChanged(object sender, DeploymentProgressChangedEventArgs e)
        {
            try
            {
                this.lblVersion.Content = string.Format("{0}: {1}% - {2} / {3} - {4}", Properties.Resources.UpdateInProgress, e.ProgressPercentage, scStringTools.FormatUnit((ulong)e.BytesCompleted, "B"), scStringTools.FormatUnit((ulong)e.BytesTotal, "B"), e.State);
            }
            catch (Exception exc)
            {
                Global.NotifyCrash(exc);
            }
        }
        void CurrentDeployment_UpdateCompleted(object sender, AsyncCompletedEventArgs e)
        {
            try
            {
                if (e.Error == null && !e.Cancelled)
                {
                    this.lblVersion.Content = Properties.Resources.RebootNeeded;
                }
                else if (e.Error != null)
                {
                    this.lblVersion.Content = e.Error.ToString();
                    this.cmdUpdate.IsEnabled = true;
                }
                else
                {
                    this.lblVersion.Content = Properties.Resources.UpdateCancelled;
                    this.cmdUpdate.IsEnabled = true;
                }
            }
            catch (Exception exc)
            {
                Global.NotifyCrash(exc);
            }
        }

        void CurrentDeployment_CheckForUpdateProgressChanged(object sender, DeploymentProgressChangedEventArgs e)
        {
            try
            {
                this.lblVersion.Content = string.Format("{0}: {1}% - {2} / {3} - {4}", Properties.Resources.UpdateSearching, e.ProgressPercentage, scStringTools.FormatUnit((ulong)e.BytesCompleted, "B"), scStringTools.FormatUnit((ulong)e.BytesTotal, "B"), e.State);
            }
            catch (Exception exc)
            {
                Global.NotifyCrash(exc);
            }
        }

        void CurrentDeployment_CheckForUpdateCompleted(object sender, CheckForUpdateCompletedEventArgs e)
        {
            try
            {
                if (e.Error == null && !e.Cancelled && e.UpdateAvailable)
                {
                    this.cmdUpdate.Visibility = System.Windows.Visibility.Visible;
                    if (!e.IsUpdateRequired && e.AvailableVersion > ApplicationDeployment.CurrentDeployment.CurrentVersion)
                        this.lblVersion.Content = string.Format("{0}: {1}", Properties.Resources.UpdateAvailable, e.AvailableVersion);
                    else
                    {
                        lblVersion.Content = string.Format("{0}", Properties.Resources.UpdateNeeded);
                        ApplicationDeployment.CurrentDeployment.Update();
                        System.Diagnostics.Process.Start(Application.ResourceAssembly.Location);
                        Application.Current.Shutdown();
                    }
                }
                else
                {
                    this.cmdUpdate.Visibility = System.Windows.Visibility.Hidden;
                    this.lblVersion.Content = string.Format("{0}: {1}", Properties.Resources.CurrentVersion, ScarecrowLibrary.scEnvironment.ApplicationVersion);
                }
            }
            catch (Exception exc)
            {
                Global.NotifyCrash( exc);
            }
        }
        #endregion
        #endregion
    }
}